from flask import request, send_from_directory, make_response, send_file
import os
import copy
import uuid
import math

from utils.common_import import *
from .model import *
from utils.ext import inner_db, db_add_record, db_update_record, db_delete_record, db_transaction, db_query_record

ORDER_ATTACH_PATH = os.getenv("ORDER_ATTACH_PATH", "/opt/order/attach")
SAFEHASH = [x for x in "0123456789-abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ"]

STATUS_PENDIND = 0
STATUS_FINISHED = 1
STATUS_DELETED = 2

def compress_UUID():
    '''
    根据http://www.ietf.org/rfc/rfc1738.txt,由uuid编码扩大字符域生成串
    包括: [0-9a-zA-Z\-_] 共64个
    长度: (32-2)/3*2 = 20
    备注: 可在地球上人人都用,使用100年不重复(2^120)
    :return:String
    '''
    row = str(uuid.uuid4()).replace('-', '')
    safe_code = 'G'
    for i in range(10):
        enbin = "%012d" % int(bin(int(row[i * 3] + row[i * 3 + 1] + row[i * 3 + 2], 16))[2:], 10)
        safe_code += (SAFEHASH[int(enbin[0:6], 2)] + SAFEHASH[int(enbin[6:12], 2)])
    return safe_code


class FaultKindOp(Resource):
    @exception_response()
    def get(self):
        data = db_query_record(FaultKind)
        return make_success_response(data)

    @permission_auth("admin")
    @request_arg_check(FaultKindAdd())
    @exception_response()
    @db_transaction(inner_db.session)
    def post(self):
        db_add_record(inner_db.session, FaultKind, {}, current_schema_instance)
        return make_no_data_response(status=200, code=0, message="add fault kind success")

    @permission_auth("admin")
    @request_arg_check(FaultKindUpdate())
    @exception_response()
    @db_transaction(inner_db.session)
    def put(self):
        db_update_record(inner_db.session,
                         FaultKind,
                         dict(id=current_schema_instance["id"]),
                         current_schema_instance)

        return make_no_data_response(status=200, code=0, message="update fault kind success")

    @permission_auth("admin")
    @request_arg_check(FaultKindDelete())
    @exception_response()
    @db_transaction(inner_db.session)
    def delete(self):
        db_delete_record(inner_db.session,
                         FaultKind,
                         dict(id=current_schema_instance))

        return make_no_data_response(status=200, code=0, message="delete fault kind success")

class WorkOrderReq(Resource):
    @request_arg_check(WorkOrderGet(), many=False, location="args")
    @exception_response()
    def get(self):

        request_info = current_schema_instance
        result = inner_db.session\
            .query(WorkOrder.id, WorkOrder.uuid, FaultKind.name_cn,
                   WorkOrder.priority, WorkOrder.username, WorkOrder.tel,
                   WorkOrder.email, WorkOrder.description, WorkOrder.create_time,
                   WorkOrder.status,
                   WorkOrder.handler, WorkOrder.handle_time, WorkOrder.handle_result) \
            .outerjoin(FaultKind, WorkOrder.kind == FaultKind.id)\
            .filter(WorkOrder.uuid == request_info["uuid"], WorkOrder.status != STATUS_DELETED) \
            .order_by(WorkOrder.status).order_by(WorkOrder.create_time.desc())\
            .paginate(request_info["page_index"],
                      request_info["per_page_items"],
                      False)
        items = []
        keys = ["id", "uuid", "kind", "priority", "username", "tel",
                "email", "description", "create_time", "status", "handler",
                "handle_time", "handle_result"]
        for item in result.items:
            item_dict = dict(zip(keys, item))
            # print(item_dict)
            items.append(item_dict)

        data = dict(items=items, total_page=result.pages)

        return make_success_response(data)

    def _generate_attach_dirname(self, reqeust_info):
        if 'attach' not in request.files:
            return
        file = request.files.get("attach")

        reqeust_info["attach"] = file.filename

        dst_dir = os.path.join(ORDER_ATTACH_PATH, "{}/{}".format(reqeust_info["uuid"], reqeust_info["id"]))
        os.makedirs(dst_dir)

        file.save(os.path.join(dst_dir, file.filename))

    @request_arg_check(WorkOrderAdd(), many=False, location="form")
    @exception_response()
    @db_transaction(inner_db.session)
    def post(self):
        request_info = copy.deepcopy(current_schema_instance)
        #request_info["id"] = str(uuid.uuid4())
        request_info["id"] = compress_UUID()

        self._generate_attach_dirname(request_info)

        db_add_record(inner_db.session,
                      WorkOrder,
                      dict(id=request_info["id"]),
                      request_info)

        return make_no_data_response(status=200, code=0, message="submit success")

    @request_arg_check(WorkOrderUpdate(), many=False, location="json")
    @exception_response()
    @db_transaction(inner_db.session)
    def put(self):
        request_info = copy.deepcopy(current_schema_instance)

        db_update_record(inner_db.session,
                      WorkOrder,
                      dict(id=request_info["id"]),
                      request_info)

        return make_no_data_response(status=200, code=0, message="update success")

    @request_arg_check(WorkOrderDelete(), many=False, location="json")
    @exception_response()
    @db_transaction(inner_db.session)
    def delete(self):
        request_info = copy.deepcopy(current_schema_instance)

        results = db_query_record(WorkOrder, dict(id=request_info["id"]))
        if not results:
            return make_error_response(status=500, code=500, message="record does not exist")

        for result in results:
            if result["uuid"] != request_info["uuid"]:
                return make_error_response(status=500, code=500, message="user does not match")

        db_update_record(inner_db.session,
                      WorkOrder,
                      dict(id=request_info["id"]),
                      dict(status=STATUS_DELETED))

        return make_no_data_response(status=200, code=0, message="update success")


class WorkOrderBak(Resource):
    @request_arg_check(OrderBackendGetSchema(), location="args")
    @exception_response()
    def get(self):
        request_info = current_schema_instance
        result = inner_db.session\
            .query(WorkOrder.id, WorkOrder.uuid, FaultKind.name_cn,
                   WorkOrder.priority, WorkOrder.username, WorkOrder.tel,
                   WorkOrder.email, WorkOrder.description, WorkOrder.create_time,
                   WorkOrder.status, WorkOrder.attach,
                   WorkOrder.handler, WorkOrder.handle_time, WorkOrder.handle_result) \
            .outerjoin(FaultKind, WorkOrder.kind == FaultKind.id).filter()\
            .order_by(WorkOrder.status).order_by(WorkOrder.create_time.desc())\
            .paginate(request_info["page_index"],
                      request_info["per_page_items"],
                      False)
        items = []
        keys = ["id", "uuid", "kind", "priority", "username", "tel",
                "email", "description", "create_time", "status", "attach",
                "handler", "handle_time", "handle_result"]
        for item in result.items:
            item_dict = dict(zip(keys, item))
            items.append(item_dict)
        data = dict(items=items, total_page=result.pages)

        return make_success_response(data)


    @request_arg_check(OrderBackendUpdateSchema())
    @exception_response()
    @db_transaction(inner_db.session)
    def put(self):
        id = current_schema_instance["id"]
        handle_result = current_schema_instance["handle_result"]
        handler = current_schema_instance["handler"]
        if not handle_result:
            return make_error_response(status=500, code=500, message="handle_result is null")
        status = STATUS_FINISHED

        handle_time = time.time()*1000
        update_info = dict(id= id, handle_result=handle_result,
                                            status = status,
                                            handle_time = handle_time,
                                            handler = handler)

        db_update_record(session= inner_db.session,
                         table_schema= WorkOrder,
                         filter_info= dict(id=id),
                         update_info= update_info)

        return make_no_data_response(status=200, code=200, message="success")

class DownloadManager(Resource):
    @request_arg_check(DownloadGetSchema(), location="args")
    @exception_response()
    def get(self):
        request_info = current_schema_instance
        FILE_FOLDER = os.path.join(ORDER_ATTACH_PATH, "{}/{}".format(request_info["uuid"], request_info["id"]))
        file_name = request_info["file_name"]

        if os.path.isfile(os.path.join(FILE_FOLDER, file_name)):
            return send_from_directory(FILE_FOLDER, file_name, as_attachment=True)

        return make_error_response(status=403, code=403, message="file not found")
